#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <getopt.h>
#include <sqlite3.h>

static int callback(void *NotUsed, int argc, char **argv, char **azColName){
   int i;
   for(i=0; i<argc; i++){
      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;
}

void getArr(char *str,char **arr);
void print_usage(char *progname)
{
	printf("%s usage: \n",progname);
	//printf("-i(--ipaddr): specify server IP address.\n");
	printf("-p(--port): specify server listen  port.\n");
	printf("-h(--Help): print this help information.\n");

	return;
}

int main (int argc,char *argv[])
{
	int			socket_fd;
	int			client_fd;
	int			rv = -1;
	struct sockaddr_in	server_addr;
	struct sockaddr_in	client_addr;
	socklen_t		cliaddr_len;
	char			buf[1024];
	char			*server_ip;
	int			port;
	int			ch = 0;
	int			on = 1;
	sqlite3			*db;
	int			rc;
	char			sql[150];
	char			*zErrMsg = 0;

	const char* data = "Callback function called";
	struct option		opts[] = {
		//{"ipaddr",required_argument,NULL,'i'},
		{"port",required_argument,NULL,'p'},
		{"help",no_argument,NULL,'h'},
		{NULL,0,NULL,0}
	};


	while((ch = getopt_long(argc,argv,"p:h",opts,NULL)) != -1)
	{
		switch(ch)
		{
			/*case 'i':
				server_ip = optarg;
				break;
			*/
			case 'p':
				port = atoi(optarg);
				break;
			case 'h':
				print_usage(argv[0]);
				return 0;
		}
	}

	if( !port )
	{
		print_usage(argv[0]);
		return 0;
	}
	//printf("%s usage: \n",progname);
	socket_fd = socket(AF_INET,SOCK_STREAM,0);
	if(socket_fd < 0)
	{
		printf("Create socket failure: %s\n",strerror(errno));
		return -1;
	}
	printf("Create socket[%d] successful!\n",socket_fd);
	
	setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));


	
	memset(&server_addr,0,sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	rv = bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
	if(rv<0)
	{
		printf("Socket[%d] bind on port[%d] failure: %s\n",socket_fd,port,strerror(errno));
		return -2;
	}

	listen(socket_fd,13);
	printf("Start to listen on port[%d]\n",port);

       	/*Open database*/
        rc = sqlite3_open("RPI.db",&db);
        if(rc)
        {   
                printf("Open database failure: %s\n",sqlite3_errmsg(db));
                return -1; 
        }   
        printf("Open database successfully\n");

	while(1)
   {
	printf("Start accept new client incoming...\n");
	client_fd = accept(socket_fd,(struct sockaddr *)&client_addr,&cliaddr_len);
	if(client_fd < 0)
	{
		printf("Accept new client failure: %s\n",strerror(errno));
		continue;
	}
	printf("Accept new client[%s:%d] with client_fd[%d]\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),client_fd);

	

	memset(buf,0,sizeof(buf));
	rv = read(client_fd,buf,sizeof(buf));
	if( rv < 0 )
	{
		printf("Read data from client by client_fd[%d] failure: %s\n ",client_fd,strerror(errno));
		return -4;
	}
	else if( rv == 0)
	{
		printf("client_fd[%d] get disconnected\n",client_fd);
		return -5;
	}
	printf("Read %d bytes data from server :%s\n",rv,buf);
	printf("MSG:%s\n",buf);

	char *arr[3];
	getArr(buf,arr);
	printf("get: %s\n",arr[0]);
	printf("get: %s\n",arr[1]);
	printf("get: %s\n",arr[2]);
	

	
	/*Creat SQL statement*/
	memset(sql,0,sizeof(sql));
	snprintf(sql,sizeof(sql),"INSERT INTO RPI (SN,DATE,TEMPERATURE)VALUES('%s','%s','%s');",arr[0],arr[1],arr[2]);
	sql[149] = '\0';
	printf("sql:%s\n",sql); 
	rc = sqlite3_exec(db,sql,0,0,&zErrMsg);
	if(rc!=SQLITE_OK)	
	{	sqlite3_close(db);
		printf("INSERT DTAA FAILURE: %s\n",zErrMsg);
		sqlite3_free(zErrMsg);
	}
	printf("INSERT DATA successfully\n");

	close(client_fd);
   }
	
	close(socket_fd);
	sqlite3_close(db);
	return 0;
}

void getArr(char *str,char **arr)
{
	arr[1] = strchr(str,'/') + 1;
	arr[2] = strrchr(str,'/') + 1;
	int sta_addr = arr[1] - str;
	int end_addr = arr[2] - str;
	arr[0] = str;
	arr[0][sta_addr-1]= '\0';
	arr[0][end_addr-1]= '\0';
	return;
}
